package engine.systems.motion.motion
{
	import engine.classes.enumerations.SystemPriority;
	import engine.systems.update.GameSystem;
	
	public class MotionSystem extends GameSystem
	{
		public function MotionSystem()
		{
			super(MotionNode, updateNode);
			
			this.priority = SystemPriority.MOTION;
		}
		
		private function updateNode(node:MotionNode, time:Number):void
		{
			var motion:Motion = node.motion;
			
			if(motion.locked) return;
			
			//Acceleration
			motion.velocityX 			+= motion.accelerationX * time;
			motion.velocityY 			+= motion.accelerationY * time;
			motion.velocityRotation 	+= motion.accelerationRotation * time;
			
			motion.velocityX 			= this.limitRange(motion.velocityX, motion.minX, motion.maxX);
			motion.velocityY 			= this.limitRange(motion.velocityY, motion.minY, motion.maxY);
			motion.velocityRotation 	= this.limitRange(motion.velocityRotation, motion.minRotation, motion.maxRotation);
			
			//Friction
			if(motion.frictionX == motion.frictionY)
			{
				var velocity:Number = Math.sqrt((motion.velocityX * motion.velocityX) + (motion.velocityY * motion.velocityY));
				var radians:Number = Math.atan2(motion.velocityY, motion.velocityX);
				
				var friction:Number = motion.frictionX * time;
				
				if(velocity > friction)
				{
					velocity -= friction;
					
					motion.velocityX = Math.cos(radians) * velocity;
					motion.velocityY = Math.sin(radians) * velocity;
				}
				else { motion.velocityX = motion.velocityY = 0; }
			}
			else
			{
				motion.velocityX = this.setFriction(motion.velocityX, motion.frictionX * time);
				motion.velocityY = this.setFriction(motion.velocityY, motion.frictionY * time);
			}
			
			motion.velocityRotation = this.setFriction(motion.velocityRotation, motion.frictionRotation * time);
			
			//Spatial
			node.spatial.x 			+= motion.velocityX * time;
			node.spatial.y 			+= motion.velocityY * time;
			node.spatial.rotation 	+= motion.velocityRotation * time;
		}
		
		private function limitRange(number:Number, min:Number, max:Number):Number
		{
			if(Math.abs(number) > max)
			{
				if(number > max) 		number = max;
				else if(number < -max) 	number = -max;
			}
			else if(Math.abs(number) < min)
			{
				if(number < min) 		number = min;
				if(number > -min)		number = -min;
			}
			return number;
		}
		
		/**
		 * Helper function for applying Friction to an Entity's Velocity.
		 * 
		 * @param Velocity: A Velocity variable to apply Friction to.
		 * @param Friction: A Friction variable to apply to the Velocity.
		 */
		private function setFriction(velocity:Number, friction:Number):Number
		{
			if(friction == 0) return velocity;
			
			if(velocity > friction) 		velocity -= friction;
			else if(velocity < -friction) 	velocity += friction;
			else 							velocity = 0;
			
			return velocity;
		}
	}
}